#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <errno.h>

#define BUFFER_SIZE 1024
#define MAX_NAME_LENGTH 50

int client_socket;  // Linux下套接字用int表示（Windows用SOCKET）
int running = 1;    // 控制程序运行状态的全局变量

// 接收消息的线程函数（POSIX线程函数返回值为void*）
void* receive_messages(void* arg) {
    char buffer[BUFFER_SIZE];
    ssize_t bytes_read;  // Linux下recv返回ssize_t（带符号整数，支持-1表示错误）

    while (running) {
        // 接收服务器消息，清空缓冲区避免残留
        memset(buffer, 0, BUFFER_SIZE);
        bytes_read = recv(client_socket, buffer, BUFFER_SIZE - 1, 0);

        if (bytes_read > 0) {
            // 消息末尾补'\0'确保字符串完整
            buffer[bytes_read] = '\0';
            printf("%s", buffer);
            printf("> ");
            fflush(stdout);  // 强制刷新输出缓冲区，避免消息显示延迟
        }
        else if (bytes_read == 0) {
            // bytes_read=0表示服务器主动关闭连接
            printf("\n服务器已断开连接\n");
            break;
        }
        else if (running) {
            // 仅在程序运行中处理错误（避免线程退出时的无效错误打印）
            perror("接收消息失败");  // Linux用perror打印系统错误信息
            break;
        }
    }

    running = 0;  // 通知主线程退出
    return NULL;
}

int main(int argc, char* argv[]) {
    struct sockaddr_in server_addr;
    char buffer[BUFFER_SIZE];
    char name[MAX_NAME_LENGTH];
    pthread_t recv_thread;  // POSIX线程ID（Windows用HANDLE）
    char* ip;
    int port;
    int ret;  // 存储函数返回值，用于错误判断

    // 检查命令行参数（格式：./client <服务器IP> <端口号>）
    if (argc != 3) {
        fprintf(stderr, "用法: %s <服务器IP> <端口号>\n", argv[0]);
        return 1;
    }

    ip = argv[1];
    port = atoi(argv[2]);  // 将字符串端口号转为整数

    // 获取用户名（支持带空格的用户名，用fgets读取整行）
    printf("请输入你的用户名: ");
    if (fgets(name, MAX_NAME_LENGTH - 1, stdin) != NULL) {
        // 移除fgets读取的换行符（\n）
        size_t newline_pos = strcspn(name, "\n");
        name[newline_pos] = '\0';
    }
    else {
        // 读取失败时默认使用"匿名用户"
        strncpy(name, "匿名用户", MAX_NAME_LENGTH - 1);
        name[MAX_NAME_LENGTH - 1] = '\0';  // 确保字符串结尾
    }

    // 1. 创建客户端套接字（Linux下socket返回int，-1表示失败）
    client_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (client_socket == -1) {
        perror("创建socket失败");
        return 1;
    }

    // 2. 设置服务器地址结构
    memset(&server_addr, 0, sizeof(server_addr));  // 清空地址结构
    server_addr.sin_family = AF_INET;              // IPv4协议
    server_addr.sin_port = htons(port);            // 端口号转网络字节序（大端）

    // 3. 转换IP地址（inet_pton兼容IPv4/IPv6，比inet_addr更安全）
    if (inet_pton(AF_INET, ip, &server_addr.sin_addr) <= 0) {
        perror("无效的IP地址");
        close(client_socket);  // Linux用close关闭套接字
        return 1;
    }

    // 4. 连接到服务器
    ret = connect(client_socket, (struct sockaddr*)&server_addr, sizeof(server_addr));
    if (ret == -1) {
        perror("连接服务器失败");
        close(client_socket);
        return 1;
    }

    printf("已连接到聊天室服务器\n");
    printf("输入消息并按回车发送，输入 'exit' 退出\n");

    // 5. 发送用户名到服务器
    ret = send(client_socket, name, strlen(name), 0);
    if (ret == -1) {
        perror("发送用户名失败");
        close(client_socket);
        return 1;
    }

    // 6. 创建接收消息的线程（POSIX线程创建函数pthread_create）
    ret = pthread_create(&recv_thread, NULL, receive_messages, NULL);
    if (ret != 0) {
        fprintf(stderr, "创建线程失败: %s\n", strerror(ret));  // 打印线程错误
        close(client_socket);
        return 1;
    }

    // 7. 主线程：读取用户输入并发送消息
    while (running) {
        printf("> ");
        fflush(stdout);  // 强制显示输入提示符

        // 读取用户输入（整行读取，支持带空格的消息）
        if (fgets(buffer, BUFFER_SIZE - 1, stdin) == NULL) {
            break;  // 读取失败（如Ctrl+D），退出循环
        }

        // 移除输入中的换行符
        size_t newline_pos = strcspn(buffer, "\n");
        buffer[newline_pos] = '\0';

        // 检查用户是否输入"exit"退出
        if (strncmp(buffer, "exit", 4) == 0) {
            running = 0;
            break;
        }

        // 给消息末尾补换行符，保持与服务器消息格式一致
        strncat(buffer, "\n", BUFFER_SIZE - strlen(buffer) - 1);

        // 发送消息到服务器
        ret = send(client_socket, buffer, strlen(buffer), 0);
        if (ret == -1) {
            perror("发送消息失败");
            running = 0;
            break;
        }
    }

    // 8. 等待接收线程结束（避免线程资源泄漏）
    pthread_join(recv_thread, NULL);  // POSIX线程等待函数

    // 9. 清理资源
    close(client_socket);  // 关闭套接字
    printf("已断开与服务器的连接\n");
    return 0;
}